#include <iostream>
using namespace std;
#include "Test.h"
#include "Test2.h"
#include "Test3.h"
#include "Test4.h"
#include "Location.h"

//给对象搭建一个舞台,研究对象的行为
void objplay(){
        //1.先创建对象, 后释放
        //t1先创建的所以后释放
        Test t1;
        t1.print();

        cout<<"------------------------"<<endl;

        Test t2;
        t2.print();
}

int main01(int argc, char const *argv[]){
        objplay();
        return 0;
}

//调用无参构造函数
void objectPlay(){
        Test2 t1;
}

//调用有参构造函数 有3种方法
void objectPlay1(){
        //1.括号法 c++编译器自动调用构造函数
        Test2 t1(1, 2);  
        
        //2.等号法
        Test2 t2 = (3, 4, 5, 6, 7); // = c++对等号操作符 进行了功能增强 c++编译器自动调用构造函数
        Test2 t3  = 5;  //c++编译器自动调用构造函数
        
        //3.直接调用构造函数 手动的调用构造函数
        Test2 t4 = Test2(1,2); //其实是一个匿名对象转成t4   现在c++版本只调用一次 早期c++调用两次 (匿名对象的去和留)

        t1 = t4; //这个时候不是t1初始化 是把t4拷贝给t1 //赋值操作

        //对象初始化 和 对象赋值 是两个不同的概念
}

//为什么需要构造函数和析够函数
void objectPlay2(){
        //类没有提供构造函数 c++编译器会自动给程序员提供一个默认的无参构造函数
        //类没有提供拷贝构造函数 c++编译器会自动给程序员提供一个拷贝参构造函数 是浅拷贝
        Test3 t1; 
        int a = 10;
        int b = 20;
        t1.init(a, b);

        Test3 tArray[3];
        tArray[0].init(1,2);
        tArray[1].init(1,2);
        tArray[2].init(1,2);

        Test3 t21; t21.init(1,2);
        Test3 t22; t22.init(1,2);
        Test3 t23; t23.init(1,2);
        //在这种场景之下 显示的初始化方案，显得很笨拙
        Test3 ttArray[3] = {t21, t22, t23};

        //这种情况下满足不了编程了
        //Test3 tttArray[1999] = {t21, t22, t23,...}
}

//赋值(拷贝)构造函数的调用时机
//赋值(拷贝)构造函数 用1个对象去初始化另外一个对象
//其实是匿名对象转为该对象
void objectPlay3(){
        Test4 t1(1,2);
        Test4 t0(1,2);

        //赋值=操作 会不会调用赋值(拷贝)构造函数？ 不会 但是可以操作符重载
        t0 = t1; //用t1给t0赋值  对象初始化 和 对象赋值 是两个不同的概念

        //第一种调用时机
        Test4 t2 = t1; //用t1来初始化t2
        t2.print();
}
//赋值(拷贝)构造函数的调用时机 第二种调用时机
void objectPlay4(){
        Test4 t1(1,2);
        Test4 t2(3,4);

        Test4 t3(t2); //用t2来初始化t3
        t3.print();
}
int main02(int argc, char const *argv[])
{
        objectPlay();
        objectPlay1();
        objectPlay3();
        objectPlay4();
        return 0;
}
//赋值(拷贝)构造函数的调用时机 第三种调用时机
//业务函数 形参是一个元素
void func(Location p){
        cout<<p.getX()<<endl;
}
void objectPlay5(){
        Location a(1, 2);
        Location b = a;
        cout<<"b对象已经初始化完毕"<<endl;

        func(b);//b实参初始化形参p， 会调用拷贝构造函数
}
//gg函数 返回一个元素
//结论: 函数的返回值是一个元素 (复杂数据类型) 返回的是一个新的匿名对象(所以会调用匿名对象的类的拷贝构造函数)
//匿名对象的去和留
//你这么写代码 设计c++编译器的大牛们:
//我就给你返回一个新的对象 只不过没有名字 匿名
Location gg(){
        Location A(1,3);
        return A; //return A   使用拷贝构造函数给匿名对象nm初始化 A析够掉 将匿名对象nm返回出去
}
void objectPlay6(){
        gg(); //这个地方匿名对象没有人用 匿名对像析够调
}
void objectPlay7(){
        //匿名对象初始化m 此时c++编译器 直接把匿名对象转成m (扶正) 从匿名转成有名对象m
        Location m = gg();
        cout<<"匿名对象 被扶正，不会析够掉"<<endl;
        cout<<m.getX()<<endl;
}
void objectPlay8(){
        Location m2(1,2 );
        m2 = gg();
        cout<<"因为用匿名对象=给m2, 匿名对象会析够掉"<<endl;
        cout<<m2.getX()<<endl;
}
int main(int argc, char const *argv[])
{
        //objectPlay5();
        // objectPlay6();
        //objectPlay7();
        objectPlay8();
        return 0;
}